home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Games Collection 1
/
software vault.zip
/
software vault
/
CDR10
/
ACK3D.ZIP
/
ENGINE
/
ACKVIEW.ENG
< prev
next >
Wrap
Text File
|
1993-08-16
|
16KB
|
596 lines
/******************* ( Animation Construction Kit 3D ) ***********************/
/* Build Current Viewport */
/* CopyRight (c) 1993 Author: Lary Myers */
/*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <mem.h>
#include <alloc.h>
#include <io.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys\stat.h>
#include "ack3d.h"
#include "ackeng.h"
#include "ackext.h"
void draw_col2(int Col,int slice,int dist,int width,int ht,UCHAR far *Wall,UCHAR far *Screen,UCHAR far *PalTable,int LightFlag);
void AckCopyBackground(UCHAR far *scrn,UCHAR far *bkgd,int len,int offset);
void DrawSlices(ACKENG *ae);
void FindObject(int xPlayer,int yPlayer,int PlayerAngle,ACKENG *ae);
UINT xRay(int x,int y,int angle,ACKENG *ae);
UINT yRay(int x,int y,int angle,ACKENG *ae);
int FindDoor(int MapPosn,ACKENG *ae);
long long_sqrt(long v);
void CheckDoors(ACKENG *ae);
extern UCHAR xLight;
extern UCHAR yLight;
/****************************************************************************
** **
****************************************************************************/
int AckBuildView(ACKENG *ae)
{
int i,j,index,xPlayer,yPlayer,PlayerAngle;
UINT xBitmap,yBitmap,BitmapNumber;
int ViewAngle;
int DoorOpenColumn;
long xDistance,yDistance;
long WallDistance;
int distance,LightAdj;
UINT BitmapColumn,yBitmapColumn;
int OldMapPosn,OldMapPosn1;
long xd,yd;
UINT offset;
CheckDoors(ae);
xPlayer = ae->xPlayer;
yPlayer = ae->yPlayer;
PlayerAngle = ae->PlayerAngle;
/* Begin looking 30 degrees to the left of our current angle */
ViewAngle = PlayerAngle - INT_ANGLE_30;
if (ViewAngle < 0)
ViewAngle += INT_ANGLE_360;
MaxDistance = 0;
LightAdj = 0;
/* Cast two rays for each column of the video display */
for (i = 0; i < VIEW_WIDTH; i++)
{
WallDistance = 3000000; /* Set to a ridiculous distance */
BitmapColumn = -1; /* Set to no walls found */
/* Don't even cast an X ray if impossible to intersect the X walls */
if (ViewAngle != INT_ANGLE_90 && ViewAngle != INT_ANGLE_270)
{
BitmapNumber = xRay(xPlayer,yPlayer,ViewAngle,ae);
if (BitmapNumber) /* A wall was found */
{
/* Use the Y intercept to determine the wall column */
BitmapColumn = (LastY1 >> FP_SHIFT) & 0x3F;
/* Keep the orientation the same no matter which side we're on */
if ((int)iLastX < xPlayer)
BitmapColumn = 63 - BitmapColumn;
/* Did we strike a door? */
if ((BitmapNumber & 0xFF) == DOOR_XCODE)
{
index = FindDoor(xMapPosn,ae);
if (index >= 0) /* This is a valid door */
{
j = ae->Door[index].ColOffset; /* Get its current pos */
offset = 0;
if (BitmapNumber & DOOR_TYPE_SLIDE)
{
DoorOpenColumn = 63;
if ((int)iLastX > xPlayer) /* Handle orientation */
j = -j;
BitmapColumn += j; /* Adjust column to show */
}
if (BitmapNumber & DOOR_TYPE_SPLIT)
{
DoorOpenColumn = 31;
if (BitmapColumn < 32)
{
BitmapColumn += j;
if (BitmapColumn > 31)
offset = 1;
}
else
{
BitmapColumn -= j;
if (BitmapColumn < 32)
offset = 1;
}
}
if (offset == 1 || BitmapColumn > 63)
{
/* Get the grid coordinates for this door */
OldMapPosn = ae->Door[index].mPos;
OldMapPosn1 = ae->Door[index].mPos1;
/* Fake the engine into thinking no door is there */
ae->xGrid[OldMapPosn] = 0;
ae->xGrid[OldMapPosn1] = 0;
/* Cast the ray to get walls beyond the door */
BitmapNumber = xRay(xPlayer,yPlayer,ViewAngle,ae);
/* Put back the door codes if not fully open */
if (ae->Door[index].ColOffset < DoorOpenColumn)
{
ae->xGrid[OldMapPosn] = ae->Door[index].mCode;
ae->xGrid[OldMapPosn1] = ae->Door[index].mCode1;
}
/* Calc the new bitmap column of wall behind door */
BitmapColumn = (LastY1 >> FP_SHIFT) & 0x3F;
if ((int)iLastX < xPlayer)
BitmapColumn = 63 - BitmapColumn;
}
}
}
/* Calculate the distance to the wall. Since the X position was */
/* fixed to move 64 or -64 we can use it to determine the actual */
/* wall distance. The InvCosTable values were stored with a fixed */
/* point of 20 decimal places. At this time we'll knock off 14 of */
/* them so we can later multiply with a fixed point value of 16 */
xd = iLastX - xPlayer;
WallDistance = (xd * InvCosTable[ViewAngle]) >> 14;
/* Still looking for the reason this may occur. But this check */
/* will force the distance to a ridiculous value so no wall is */
/* seen later on when the X and Y walls are compared. */
if (WallDistance < 0)
WallDistance = 120000L;
LightAdj = xLight;
}
}
/* Don't cast a Y ray if its impossible to intercept any Y walls */
if (ViewAngle != 0 && ViewAngle != INT_ANGLE_180)
{
yBitmap = yRay(xPlayer,yPlayer,ViewAngle,ae);
if (yBitmap) /* A wall was found */
{
/* Use the X intercept to determine the column of the bitmap */
yBitmapColumn = (LastX1 >> FP_SHIFT) & 0x3F;
/* Handle orientation from either side of the wall */
if ((int)iLastY > yPlayer)
yBitmapColumn = 63 - yBitmapColumn;
/* Did we strike a door? */
if ((yBitmap & 0xFF) == DOOR_YCODE)
{
index = FindDoor(yMapPosn,ae);
if (index >= 0) /* This is a valid door */
{
/* Get the current door column offset */
j = ae->Door[index].ColOffset;
offset = 0;
/* Deal with orientation */
if (yBitmap & DOOR_TYPE_SLIDE)
{
DoorOpenColumn = 63;
if ((int)iLastY < yPlayer)
j = -j;
yBitmapColumn += j;
}
if (yBitmap & DOOR_TYPE_SPLIT)
{
DoorOpenColumn = 31;
if (yBitmapColumn < 32)
{
yBitmapColumn += j;
if (yBitmapColumn > 31)
offset = 1;
}
else
{
yBitmapColumn -= j;
if (yBitmapColumn < 32)
offset = 1;
}
}
/* If beyond width of bitmap than cast again */
if (offset == 1 || yBitmapColumn > 63)
{
/* Get the yGrid coordinates for this door */
OldMapPosn = ae->Door[index].mPos;
OldMapPosn1 = ae->Door[index].mPos1;
/* Fool the engine into thinking no door is there */
ae->yGrid[OldMapPosn] = 0;
ae->yGrid[OldMapPosn1] = 0;
/* Cast again for walls beyond the door */
yBitmap = yRay(xPlayer,yPlayer,ViewAngle,ae);
/* Put door code back if not fully open */
if (ae->Door[index].ColOffset < DoorOpenColumn)
{
ae->yGrid[OldMapPosn] = ae->Door[index].mCode;
ae->yGrid[OldMapPosn1] = ae->Door[index].mCode1;
}
/* Get the bitmap column of wall beyond door */
yBitmapColumn = (LastX1 >> FP_SHIFT) & 0x3F;
if ((int)iLastY > yPlayer)
yBitmapColumn = 63 - yBitmapColumn;
}
}
}
/* Calculate the distance to the wall. Since the Y position was */
/* fixed to move 64 or -64 we can use it to determine the actual */
/* wall distance. The InvSinTable values were stored with a fixed */
/* point of 20 decimal places. At this time we'll knock off 14 of */
/* them so we can later multiply with a fixed point value of 16 */
yd = iLastY - yPlayer;
yDistance = (yd * InvSinTable[ViewAngle]) >> 14;
/* Don't know the reason but change negative value into ridiculous */
if (yDistance < 0)
yDistance = 120000L;
/* At this point check the distance to the Y wall against the X */
/* wall to see which one is closer. The closer one is the one */
/* we'll draw at this column of the screen. */
if (yDistance < WallDistance)
{
WallDistance = yDistance;
BitmapNumber = yBitmap;
BitmapColumn = yBitmapColumn;
LightAdj = yLight;
}
}
}
if (BitmapColumn < 64) /* A wall was found (either X or Y) */
{
/* To avoid a fishbowl affect we need to adjust the distance so */
/* it appears perpendicular to the center point of the display */
/* which is relative angle 0 from the players current angle. We */
/* started at -30 degrees for the first screen column and will */
/* cycle from -30 down to 0 then back up to +30 degrees. This */
/* cosine value was pre-calculated and placed in ViewCosTable. */
WallDistance *= ViewCosTable[i];
/* Now we strip off somemore decimal points and check round-up */
xd = WallDistance >> 14;
if (WallDistance - (xd << 14) >= 8096)
xd++;
/* The last decimal points from the multiplication after the X and */
/* Y rays is stripped off and checked for round-up. */
WallDistance = xd >> 6;
if (xd - (WallDistance << 6) >= 32)
WallDistance++;
/* Don't really need to, but put it into an integer for fast compare */
distance = WallDistance;
/* This is an arbitrary minimum distance to look for */
if (distance < 10)
distance = 10;
/* Don't want it to go outside our table boundaries */
if (distance >= MAX_DISTANCE)
distance = MAX_DISTANCE - 1;
/* Save the wall data to display when done with entire screen */
Walls[i].Distance = distance;
Walls[i].Number = BitmapNumber & 0xFF;
Walls[i].Column = BitmapColumn;
Walls[i].LightAdj = LightAdj;
if (distance > MaxDistance)
MaxDistance = distance;
}
ViewAngle++;
if (ViewAngle >= INT_ANGLE_360)
ViewAngle -= INT_ANGLE_360;
}
DrawSlices(ae);
/* Now we look at any objects that may be closer than the walls */
FindObject(xPlayer,yPlayer,PlayerAngle,ae);
return(0);
}
/****************************************************************************
** **
****************************************************************************/
void DrawSlices(ACKENG *ae)
{
int i,x1,wt,ht,LightFlag;
UCHAR far *wall,*ScreenBuffer;
UCHAR far *pTable;
UCHAR far **bmaps;
AckCopyBackground(ae->ScreenBuffer,ae->BkgdBuffer,ae->WinLength,ae->WinStartOffset);
x1 = ae->WinEndX;
ht = ae->CenterRow;
wt = BYTES_PER_ROW;
ScreenBuffer = ae->ScreenBuffer;
bmaps = ae->bMaps;
pTable = ae->PalTable;
LightFlag = ae->LightFlag;
for (i = ae->WinStartX; i < x1; i++)
{
wall = AckGetBitmapPtr(Walls[i].Number,bmaps);
draw_col2(i,Walls[i].Column,Walls[i].Distance,wt,ht,wall,
ScreenBuffer,pTable,LightFlag);
}
}
/****************************************************************************
** **
****************************************************************************/
void FindObject(int xPlayer,int yPlayer,int PlayerAngle,ACKENG *ae)
{
int i,j,count,SaveCenter;
int ObjX,ObjY,ObjNum;
int NewX,NewY,LightFlag;
int MaxOpp,Column,ColBeg,ColEnd;
int wt,ObjIndex,CenterColumn;
int vidwt,vidht;
long deltax,deltay;
long xp,yp,distance;
long SinValue,CosValue;
UCHAR far *wall,*ScreenBuffer;
UCHAR far *pTable;
UCHAR far **omaps;
char mBuf[40];
vidht = ae->CenterRow;
vidwt = BYTES_PER_ROW;
ScreenBuffer = ae->ScreenBuffer;
omaps = ae->oMaps;
TotalObjects = 0;
ObjRelDist[0] = 0L;
SinValue = SinTable[PlayerAngle];
CosValue = CosTable[PlayerAngle];
/* First thing we'll do is check all the objects to see which ones may be */
/* completely out of view, and to get some initial values for later... */
for (i = 0; i < MAX_OBJECTS; i++)
{
if (!ae->ObjList[i].Active)
continue;
ObjX = ae->ObjList[i].x;
ObjY = ae->ObjList[i].y;
/* Translate the object coordinates to make relative to the POV */
NewX = ObjX - xPlayer;
NewY = ObjY - yPlayer;
if (abs(NewX) < 10 && abs(NewY) < 10)
continue;
#if 0
if (PlayerAngle > INT_ANGLE_180 && (NewY-63) > 0)
continue;
if (PlayerAngle < INT_ANGLE_180 && (NewY+63) < 0)
continue;
if (PlayerAngle > INT_ANGLE_270 || PlayerAngle < INT_ANGLE_90)
{
if ((NewX+63) < 0)
continue;
}
if (PlayerAngle < INT_ANGLE_270 && PlayerAngle > INT_ANGLE_90)
{
if ((NewX-63) > 0)
continue;
}
#endif
if ((PlayerAngle == 0 || PlayerAngle == INT_ANGLE_180) && abs(NewX) < 2)
continue;
if ((PlayerAngle == INT_ANGLE_90 || PlayerAngle == INT_ANGLE_270) &&
abs(NewY) < 2)
continue;
/* Rotate coordinates to current player angle */
xp = ((NewX * CosValue) + (NewY * SinValue)) >> FP_SHIFT;
yp = ((NewY * CosValue) - (NewX * SinValue)) >> FP_SHIFT;
if (xp <= 0)
continue;
distance = (long)long_sqrt((xp * xp) + (yp * yp));
if (distance >= MAX_DISTANCE)
continue;
/* Place the objects in the correct order so further ones are behind */
j = TotalObjects;
if (j)
{
for (count = 0; count < TotalObjects; count++)
{
if (distance > ObjRelDist[count])
{
for (j = TotalObjects; j > count; j--)
{
ObjRelDist[j] = ObjRelDist[j-1];
ObjNumber[j] = ObjNumber[j-1];
ObjDeltaX[j] = ObjDeltaX[j-1];
ObjDeltaY[j] = ObjDeltaY[j-1];
}
j = count;
count = TotalObjects;
}
}
}
/* Hold onto relavant data for the object found */
ObjNumber[j] = i;
ObjRelDist[j] = distance;
ObjDeltaX[j] = xp;
ObjDeltaY[j] = yp;
TotalObjects++;
ObjRelDist[TotalObjects] = 0L;
}
/* Didn't find any objects on the above pass, so we're done */
if (!TotalObjects)
return;
CenterColumn = ae->WinStartX + (ae->WinWidth / 2);
pTable = ae->PalTable;
LightFlag = ae->LightFlag;
for (i = 0; i < TotalObjects; i++)
{
ObjIndex = ObjNumber[i];
ObjNum = ae->ObjList[ObjIndex].bmNum[ae->ObjList[ObjIndex].CurNum];
ObjY = ae->ObjList[ObjIndex].y;
NewY = ObjY - yPlayer;
distance = ObjRelDist[i];
deltax = ObjDeltaX[i];
yp = deltay = ObjDeltaY[i];
MaxOpp = ((LongTanTable[INT_ANGLE_30] * (long)deltax) >> FP_SHIFT);
if (NewY < ObjY)
{
MaxOpp = -MaxOpp;
yp = -yp;
}
if ((yp+32) < MaxOpp)
continue;
Column = CenterColumn;
if (MaxOpp)
Column = CenterColumn - ((deltay * CenterColumn) / MaxOpp);
yp = ViewCosTable[Column];
if (yp)
{
distance = distance * yp;
xp = distance >> 14;
if (distance - (xp << 14) >= 8096)
xp++;
distance = xp;
}
if (distance < 0)
continue;
if (distance >= (MAX_DISTANCE - 10))
distance = MAX_DISTANCE-11;
wt = DistanceTable[distance];
/* Keep the width of the object reasonable */
if (wt > 300)
continue;
if (wt < 16) wt = 16;
#if 0
if (wt > 300) wt = 300;
#endif
yp = AdjustTable[distance];
xp = 0; /* First col of the object to display */
#if 0
wt >>= 1;
#endif
NewX = Column;
if (ae->ObjList[ObjIndex].Sides)
ObjNum =
ae->ObjList[ObjIndex].bmNum[((PlayerAngle / ae->ObjList[ObjIndex].Sides) & 7)];
SaveCenter = ae->CenterRow;
ae->CenterRow = ae->ObjList[ObjIndex].VidRow;
ColEnd = NewX + wt;
for (Column = NewX - wt; Column < ColEnd; Column++)
{
if (Column >= ae->WinStartX && Column <= ae->WinEndX)
{
if (distance < (Walls[Column].Distance + 10))
{
wall = AckGetBitmapPtr(ObjNum,omaps);
draw_col2(Column,xp >> FP_SHIFT,distance,vidwt,vidht,wall,
ScreenBuffer,pTable,LightFlag);
}
}
xp += yp; /* Advance the next column to display (scaling) */
}
ae->CenterRow = SaveCenter;
}
}